#region License, Terms and Conditions
//
// This Generic Dictionary Importer was added by marstone, 2010/10/25
//
#endregion

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Studio.Foundation.Json.Core.Conversion.Converters
{

    public class GenericDictionaryImporter : ImporterBase
    {

        public GenericDictionaryImporter(Type type)
            : base(type) { }


        object CreateInstance(Type outputType, out Type[] args)
        {
            args = this.OutputType.GetGenericArguments();
            Debug.Assert(2 == args.Length);
            // Generic Interface
            if (true == outputType.IsInterface)
            {
                outputType = typeof(Dictionary<,>).MakeGenericType(args);
            }
            object o = Activator.CreateInstance(outputType);
            return o;
        }
        
        protected override object ImportFromArray(ImportContext context, JsonReader reader)
        { 
            Debug.Assert(context != null);
            Debug.Assert(reader != null);
            Type outputType = this.OutputType;
            Type[] args;
            object o = this.CreateInstance(outputType, out args);

            reader.Read();
            while (reader.TokenClass != JsonTokenClass.EndArray)
            {
                Type elementType = typeof(KeyValuePair<,>).MakeGenericType(args);
                object pair = context.Import(elementType, reader);
                KeyValuePair<string, string> s;

                object key = elementType.GetProperty("Key").GetValue(pair, null);
                object value = elementType.GetProperty("Value").GetValue(pair, null);

                this.OutputType.InvokeMember("Add",
                    System.Reflection.BindingFlags.InvokeMethod |
                    System.Reflection.BindingFlags.Public |
                    System.Reflection.BindingFlags.Instance,
                    null, o, new object[] { key, value }); 
            }
            
            return o;
        }
        

        protected override object ImportFromObject(ImportContext context, JsonReader reader)
        {
            Debug.Assert(context != null);
            Debug.Assert(reader != null);
            Type outputType = this.OutputType;
            Type[] args;
            object o = this.CreateInstance(outputType, out args);

            reader.Read();
            
            while (reader.TokenClass != JsonTokenClass.EndObject)
            {
                string memberName = reader.ReadMember();
                object key = null;
                if (typeof(string) == args[0])
                {
                    key = memberName;
                }
                else if (typeof(int) == args[0])
                {
                    int i;
                    if (false == int.TryParse(memberName, out i)) continue;
                    key = i;
                }
                else if (typeof(bool) == args[0])
                {
                    bool b;
                    if (false == bool.TryParse(memberName, out b)) continue;
                    key = b;
                }
                else if (typeof(double) == args[0])
                {
                    double d;
                    if (false == double.TryParse(memberName, out d)) continue;
                    key = d;
                }
                else if (typeof(float) == args[0])
                {
                    float f;
                    if (false == float.TryParse(memberName, out f)) continue;
                    key = f;
                }
                else if (typeof(decimal) == args[0])
                {
                    decimal d;
                    if (false == decimal.TryParse(memberName, out d)) continue;
                    key = d;
                }
                else
                {
                    continue;
                }

                object value = context.Import(args[1], reader);

                this.OutputType.InvokeMember("Add", 
                    System.Reflection.BindingFlags.InvokeMethod | 
                    System.Reflection.BindingFlags.Public |
                    System.Reflection.BindingFlags.Instance,

                    null, o, new object[] { key, value });
            }

            return ReadReturning(reader, o);
        }

        public static bool CanImport(Type type)
        {
            if (false == type.IsGenericType) return false;
            if (type.IsGenericTypeDefinition) return false;

            Type[] args = type.GetGenericArguments();
            if (2 != args.Length) return false;

            return typeof(IDictionary<,>).MakeGenericType(args).IsAssignableFrom(type);
        }
    }
}